home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / ccmd / test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-19  |  25.3 KB  |  1,005 lines

  1. /*
  2.  Author: Andy Lowry
  3.  Rewritten by Howie Kaye
  4.  
  5.  Columbia University Center for Computing Activities, April 1987.
  6. Copyright (C) 1986, 1987, Trustees of Columbia University in the City
  7. of New York.  Permission is granted to any individual or institution
  8. to use, copy, or redistribute this software so long as it is not sold
  9. for profit, provided this copyright notice is retained.  */
  10.  
  11. /*
  12.  * The purpose of this program is to demonstrate some of the features of
  13.  * CCMD.  It is also a way of testing the various functions of the
  14.  * interface.  Hopefully it will be instrumental in defining a style for
  15.  * writing code to use CCMD.
  16.  *
  17.  * There are certain issues addressed in several of these routines which
  18.  * are of note.
  19.  * 1) the value returned from a parse MUST be copied before the next parse.
  20.  *    The next parse will invalidate the parseval structure used.
  21.  *    This does not mean that the data pointed to becomes invalid.  Only the
  22.  *    pointer (note that for file parses, the data pointed to is reused by
  23.  *    the next file parse)
  24.  * 2) due to reparsing, multiple calls to malloc() may be done.  It is
  25.  *    important to free these pointers before the next malloc().  This is
  26.  *    similar to the problem with JFNs under COMND% in TOPS20.
  27.  */
  28.  
  29. #include "ccmd.h"
  30.  
  31. int debug = 0;
  32. /*
  33.  * forward declare parse routines.
  34.  */
  35. int octnum(), decnum(), hexnum(), key(), qst(), dst(), b5num(), exitcmd();
  36. int text(), word(), swit(), tok(), fil(), tim(), tad(), dat(), user();
  37. int groupcmd(),para(),contpara(),take(),comment(), password();
  38. int domatch(), help(), character(), shell(), nil(), history();
  39.  
  40. char *malloc();
  41. static char *atmbuf;
  42. /*
  43.  * set up the top level keyword table
  44.  * This will be used by the help command also.
  45.  */
  46.  
  47. static keywrd cmds[] = {
  48.   { "base-5",    0,    (keyval) b5num },
  49.   { "character",0,    (keyval) character },
  50.   { "comment",    0,    (keyval) comment },
  51.   { "continue",    0,    (keyval) contpara },
  52.   { "date",    0,    (keyval) dat },
  53.   { "decimal",    0,    (keyval) decnum },
  54.   { "delimited",0,    (keyval) dst },
  55.   { "exit",    0,    (keyval) exitcmd },
  56.   { "file",    0,    (keyval) fil },
  57.   { "group",    0,    (keyval) groupcmd },
  58.   { "h",     KEY_ABR|KEY_INV, (keyval) 11 },    /* abbrev for help -- index == 11 */
  59.   { "help",    0,    (keyval) help },
  60.   { "hexadecimal",0,    (keyval) hexnum },
  61.   { "history",  0,     (keyval) history },
  62.   { "line",    0,    (keyval) text },    
  63.   { "match",    0,    (keyval) domatch },
  64.   { "octal",    0,    (keyval) octnum },
  65.   { "paragraph",0,    (keyval) para },
  66.   { "password",    0,    (keyval) password },
  67.   { "person",    0,    (keyval) key },
  68.   { "q",     KEY_ABR|KEY_INV, (keyval) 21 },    /* abbrev for quit -- index == 12 */
  69.   { "quit",    KEY_INV,(keyval) exitcmd },
  70.   { "quoted",    0,    (keyval) qst },
  71.   { "switch",    0,    (keyval) swit },
  72.   { "tad",    0,    (keyval) tad },
  73.   { "take",    0,    (keyval) take },
  74.   { "time",    0,    (keyval) tim },
  75.   { "token",    0,    (keyval) tok },
  76.   { "user",    0,    (keyval) user },
  77.   { "word",    0,    (keyval) word },
  78.   { "shell",    0,    (keyval) shell },
  79.   { "nil",     KEY_INV,(keyval) nil },
  80. };
  81.  
  82. /*
  83.  * the actual keyword table type has a length in it.
  84.  */
  85. static keytab cmdtab = { (sizeof(cmds)/sizeof(keywrd)), cmds };
  86.  
  87. pval parseval;
  88. fdb *used;
  89.  
  90.  
  91. int argc;
  92. char *argv;
  93. main(Argc,Argv) int Argc; char *Argv;
  94. {
  95.   char *cmini();
  96.   argc = Argc;
  97.   argv = Argv;
  98.   atmbuf = cmini();            /* initialize ccmd */
  99.   cmhst(100);
  100.   cmxprintf("Test program Version 0.0\n"); /* display version info */
  101.   cmxprintf("%s\n",cm_version());    /* and CCMD version as well. */
  102.   toplevel();                /* top level cmd parser. */
  103.   cmdone();                /* restore terminal, etc */
  104.   return(0);
  105. }
  106.  
  107. int done = FALSE;            /* exit flag */
  108. toplevel() {
  109.                     /* FDB for top level commands */
  110.   static fdb cmdfdb = { _CMKEY, 0, NULL, (pdat) &(cmdtab), "Command, ", 
  111.               NULL, NULL };
  112.   while (!done) {
  113.     cmseter();                /* set error trap */
  114.                     /* control will come here in the */
  115.                     /* case of a parse error. */
  116.     if (cmcsb._cmerr == CMxEOF)        /* exit on EOF -- this is useful */
  117.       break;                /* for take's */
  118.     if (cmargs(argc,argv))        /* check for command line args */
  119.       done = TRUE;
  120.     else
  121.       prompt("Test> ");            /* prompt */
  122.     cmsetrp();                /* set reparse trap */
  123.                     /* control will come here in the */
  124.                     /* case of a reparse. */
  125.     parse(&cmdfdb,&parseval,&used);    /* parse a command */
  126.     execute(parseval._pvkey);        /* execute it. */
  127.   }
  128. }
  129.  
  130. /*
  131.  * execute a command.
  132.  * call the function, with the help flag off.
  133.  */
  134. execute(f) int (*f)(); {
  135.   (*f)(FALSE);                /* call function with help flag off */
  136. }
  137.  
  138. /*
  139.  * call a command function with the help flag on
  140.  */
  141. dohelp(f) int (*f)(); {
  142.   (*f)(TRUE);                /* call function with help flag on */
  143. }
  144.  
  145.  
  146. /*
  147.  * top level commands.
  148.  * all of these take the form 
  149.  * command(helpflag) {
  150.  *   if (helpflag) print a help string
  151.  *   else { parse and execute }
  152.  *
  153.  * this style is encouraged, as the documentation for each command
  154.  * resides inside the command itself.  This leads to self documenting
  155.  * parses, and documentation which is consistant with the code.
  156.  */
  157.  
  158. key(helpflg) int helpflg; {
  159. /*
  160.  * keyword table for the name command
  161.  */
  162.   static keywrd keys[] = {
  163.     { "andy", 0, (keyval) 1 },
  164.     { "and", KEY_NOR+KEY_INV, (keyval) 2}, /* this essentially turns off esc */
  165.                     /* completion on andy. */
  166.     { "dee", 0, (keyval) 3 },
  167.     { "doug", 0, (keyval) 4 },
  168.     { "d", KEY_ABR+KEY_INV, (keyval) 3 },
  169.     { "frank", KEY_INV, (keyval) 6 },    /* frank is invisible */
  170.     { "howie", 0, (keyval) 7 },
  171.     { "how", KEY_NOR+KEY_INV, (keyval) 8 },/*complete on howie after the 'i' */
  172.     { "mark", 0, (keyval) 9 },
  173.     { "tom.chow", 0, (keyval) 10 }    /* has a dot in it. */
  174.   };
  175.  
  176.   static keytab ktab = { (sizeof(keys)/sizeof(keywrd)), keys };
  177.  
  178. /* 
  179.  * custom break table -- like the standard for keywords, but allows
  180.  * periods in other than the first position.
  181.  */
  182.  
  183.   static brktab keybrk = {
  184.     {                    /* 1st char break array */
  185.                           /* all but letters, digits, hyphen */
  186.       0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x3f, 
  187.       0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f
  188.     },
  189.     {                    /* subsequent char break array */
  190.                     /* same as above, plus dots */
  191.       0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x00, 0x3f, 
  192.       0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f
  193.     }
  194.   };
  195.     
  196.                     /* fdb for names.   default to dee */
  197.   static fdb keyfdb = { _CMKEY, 0, NULL, (pdat) &ktab, "Name, ", "dee",
  198.             &keybrk };
  199.  
  200.   static int choice;
  201.  
  202. /*
  203.  * at last, some code.
  204.  */
  205.   if (helpflg) {
  206.     cmxprintf("\
  207. The key command parses a bunch of keywords.  Actually, these are mostly\n\
  208. people's names.  There are a few ignored keywords, which prevent escape\n\
  209. completion on others.\n");
  210.   }
  211.   else {
  212.     noise("of choice is");        /* give a guide word */
  213.     parse(&keyfdb,&parseval,&used);    /* parse a keyword */
  214.     choice = parseval._pvkey;        /* remember which was chosen */
  215.     confirm();                /* confirm the request */
  216.     cmxprintf("Selected name: %s\n",keys[choice]._kwkwd);
  217.   }
  218. }
  219.  
  220. /*
  221.  * the switch command
  222.  */
  223.  
  224. swit(helpflg)
  225. int helpflg;
  226. {
  227.   static keywrd swits[] = {
  228.     { "find:", KEY_INV, (keyval) 0 },    /* invisible, takes a value */
  229.                     /* prevent completion on hello-world */
  230.     { "hell", KEY_NOR+KEY_INV, (keyval) 1 },
  231.     { "hello-world", 0, (keyval) 2 },
  232.     { "junk", 0, (keyval) 3 },
  233.     { "old", 0, (keyval) 4 },
  234.     { "qui", KEY_NOR+KEY_INV, (keyval) 5},
  235.     { "quiet", 0, (keyval) 6 },
  236.     { "s", KEY_ABR+KEY_INV, (keyval) 8 },
  237.     { "stuff:", 0, (keyval) 8 },    /* takes a value */
  238.     { "stupid", 0, (keyval) 9 },
  239.     { "time", 0, (keyval) 10 },
  240.   };
  241.  
  242.   static keytab stab = { (sizeof(swits)/sizeof(keywrd)), swits };
  243.   static fdb swifdb = { _CMSWI, 0, NULL, (pdat) &stab, NULL, "/time", NULL };
  244.   static int choice, value, valflg;
  245.   static fdb valfdb = { _CMNUM, 0, NULL, (pdat) 10, NULL, NULL, NULL };
  246.  
  247.   if (helpflg) {
  248.     cmxprintf("\
  249. The switch command parses a bunch of switches.  Switches are keywords which\n\
  250. begin with a switch character.  In this case, the switch character is '/'.\n\
  251. It is possible to change the switch character to any other character by \n\
  252. changing the 'cmswbeg' variable in ccmd.  You can do this with in this \n\
  253. program by using the 'character' command.  Type 'help character' for more\n\
  254. information about it.\n\
  255. \n\
  256. A switch may also take a value after it.  If the switch ends with a \n\
  257. colon ':', then it accepts another (integer) value.\n");
  258.   }
  259.   else {
  260.     noise("selection is");        /* some extra help */
  261.     parse(&swifdb,&parseval,&used);    /* parse the switch */
  262.     choice = parseval._pvkey;        /* remember which */
  263.     if (cmcsb._cmflg & CM_SWT) {    /* if the switch takes a value */
  264.       parse(&valfdb,&parseval,&used);    /*  parse  that too.*/
  265.       value = parseval._pvint;
  266.       valflg = TRUE;
  267.     }
  268.     else
  269.       valflg = FALSE;
  270.   }
  271.   confirm();                /* get comfirmation */
  272.   cmxprintf("Selected switch: %s\n",swits[choice]._kwkwd);
  273.   if (valflg)
  274.     cmxprintf("Switch value: %d\n",value);
  275. }
  276.  
  277. /*
  278.  * parse a hex number
  279.  */
  280. hexnum(helpflg)
  281. int helpflg;
  282. {
  283.   static int value;
  284.   static fdb hexfdb = { _CMNUM, NUM_US, NULL, (pdat) 16, NULL, NULL, NULL };
  285.  
  286.   if (helpflg)
  287.     cmxprintf("\
  288. The hexnum command accepts a Hexadecimal number, and displays it.  the\n\
  289. number is actually returned in decimal, and printed out again in \n\
  290. hexadecimal.\n");
  291.   else {
  292.     noise("number is");
  293.     parse(&hexfdb,&parseval,&used);
  294.     value = parseval._pvint;
  295.     confirm();
  296.     cmxprintf("Value: %x\n", value);
  297.   }
  298. }
  299.  
  300. /*
  301.  * parse a decimal number
  302.  */
  303. decnum(helpflg)
  304. int helpflg;
  305. {
  306.   static int value;
  307.   static fdb decfdb = { _CMNUM, 0, NULL, (pdat) 10, NULL, NULL, NULL };
  308.  
  309.   if (helpflg)
  310.     cmxprintf("\
  311. The decimal command accepts a decimal number, and displays it.\n");
  312.   else {
  313.     noise("number is");
  314.     parse(&decfdb,&parseval,&used);
  315.     value = parseval._pvint;
  316.     confirm();
  317.     cmxprintf("Value: %d\n", value);
  318.   }
  319. }
  320.  
  321. /*
  322.  * parse an octal number
  323.  */
  324. octnum(helpflg)
  325. int helpflg;
  326. {
  327.   static char *value = NULL;
  328.   static int octdat = 8;
  329.   static fdb octfdb = { _CMNUM, NUM_PO, NULL, (pdat) 8, NULL, NULL, NULL };
  330.  
  331.   if (helpflg) {
  332.     cmxprintf("The octal command accepts an octal number.\n");
  333.   }
  334.   else {
  335.     noise("number is");
  336.     parse(&octfdb,&parseval,&used);    /* parse an octal number */
  337.     if (value) {
  338.       free(value);
  339.       value = NULL;
  340.     }
  341.     value = malloc(strlen(atmbuf)+1);    /* get the string, not the number */
  342.     strcpy(value,atmbuf);        /* because printf doesn't support */
  343.     confirm();                /* the printing of octal numbers */
  344.     cmxprintf("Value: %s\n", value);
  345.     free(value);
  346.     value = NULL;
  347.   }
  348. }
  349.  
  350. /*
  351.  * a base five number
  352.  */
  353. b5num(helpflg)
  354. int helpflg;
  355. {
  356.   static int value;
  357.   static int b5dat = 5;
  358.   static fdb b5fdb = { _CMNUM, 0, NULL, (pdat) 5, NULL, NULL, NULL };
  359.  
  360.   if (helpflg)
  361.     cmxprintf("accepts a number in base 5, and displays it in decimal.\n");
  362.   else {
  363.     noise("number is");
  364.     parse(&b5fdb,&parseval,&used);
  365.     value = parseval._pvint;        /* get the number in decimal */
  366.     confirm();
  367.     cmxprintf("Value (decimal): %d\n", value); /* print it */
  368.   }
  369. }
  370.  
  371. /*
  372.  * the exit command
  373.  */
  374. exitcmd(helpflg)
  375. int helpflg;
  376. {
  377.   if (helpflg) {
  378.     cmxprintf("\
  379. The exit command exits from this program.  The invisible quit command is\n\
  380. a synonym for it.\n");
  381.   }
  382.   else {
  383.     noise("this goofy program");
  384.     confirm();
  385.     done = TRUE;            /* just set the global exitflg */
  386.   }
  387. }
  388.  
  389. /*
  390.  * parse a quoted string.
  391.  * quoted strings must be quoted by '"'.  They are a specific case of
  392.  * delimited strings.
  393.  */
  394.  
  395. qst(helpflg)
  396. int helpflg;
  397. {
  398.   static fdb qstfdb = { _CMQST, 0, NULL, NULL, NULL, NULL, NULL };
  399.   static char *valstr= NULL;
  400.   
  401.   if (helpflg) {
  402.     cmxprintf("Accepts a quoted string.\n");
  403.   }
  404.   else {
  405.     noise("string is");
  406.     parse(&qstfdb,&parseval,&used);    /* parse a string */
  407.     if (valstr) {
  408.       free(valstr);
  409.       valstr = NULL;
  410.     }
  411.     valstr = malloc(strlen(atmbuf)+1);
  412.     strcpy(valstr,atmbuf);
  413.     confirm();
  414.     cmxprintf("String: %s\n",valstr);
  415.     free(valstr);
  416.     valstr = NULL;
  417.   }
  418. }
  419.  
  420.  
  421.  
  422. /* 
  423.  * break chars for delimited parse
  424.  * only first char break chars are valid delimiters.
  425.  */
  426. static brktab dstbrk = {
  427.   {
  428.     0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01,
  429.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
  430.   },
  431.   {
  432.     0x00, 0xac, 0x25, 0x10, 0x00, 0x00, 0x00, 0x01,
  433.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
  434.   }
  435. };
  436.  
  437. dst(helpflg)
  438. int helpflg;
  439. {
  440.   static fdb dstfdb = { _CMQST, 0, NULL, NULL, NULL, NULL, &dstbrk };
  441.   static char *valstr= NULL;
  442.   
  443.   if (helpflg) {
  444.     cmxprintf("\
  445. Accepts a delimited string.  The final delimiter must match the\n\
  446. first delimiter.\n");
  447.   }
  448.   else {
  449.     noise("string is");
  450.     parse(&dstfdb,&parseval,&used);
  451.     if (valstr) {
  452.       free(valstr);
  453.       valstr = NULL;
  454.     }
  455.     valstr = malloc(strlen(atmbuf)+1);
  456.     strcpy(valstr,atmbuf);
  457.     confirm();
  458.     cmxprintf("String: %s\n",valstr);
  459.     free(valstr);
  460.     valstr = NULL;
  461.   }
  462. }
  463.  
  464. /*
  465.  * parse text.   up to a newline.
  466.  */
  467. text(helpflg)
  468. int helpflg;
  469. {
  470.   static char *valstr;
  471.   static fdb txtfdb = { _CMTXT, 0, NULL, NULL, NULL, NULL, NULL };
  472.   
  473.   if (helpflg) {
  474.     cmxprintf("Accepts an arbitrary line of text\n");
  475.   }
  476.   else {
  477.     noise("of text is");
  478.     parse(&txtfdb,&parseval,&used);
  479.     if (valstr) {
  480.       free(valstr);
  481.       valstr = NULL;
  482.     }
  483.     valstr = malloc(strlen(atmbuf)+1);
  484.     strcpy(valstr,atmbuf);
  485.     confirm();
  486.     cmxprintf("Line: %s\n",valstr);
  487.     free(valstr);
  488.     valstr = NULL;
  489.   }
  490. }
  491.  
  492. /* 
  493.  * parse a word.
  494.  * actually, a field.
  495.  */
  496. word(helpflg)
  497. int helpflg;
  498. {
  499.   static char *valstr= NULL;
  500.   static fdb wrdfdb = { _CMFLD, 0, NULL, NULL, NULL, NULL, NULL };
  501.   
  502.   if (helpflg) {
  503.     cmxprintf("Accepts a word.  Words are delimited by whitespace, or other\n\
  504. characters which are not in the current break mask.\n");
  505.   }
  506.   else {
  507.     noise("of the day is");
  508.     parse(&wrdfdb,&parseval,&used);
  509.     if (valstr) {
  510.       free(valstr);
  511.       valstr = NULL;
  512.     }
  513.     valstr = malloc(strlen(atmbuf)+1);
  514.     strcpy(valstr,atmbuf);
  515.     confirm();
  516.     cmxprintf("Word: %s\n",valstr);
  517.     free(valstr);
  518.     valstr = NULL;
  519.   }
  520. }
  521.  
  522.  
  523. /*
  524.  * parse a token.
  525.  * use the chainfdb call.   this actually modifies the fdbs, so be careful.
  526.  */
  527. tok(helpflg)
  528. int helpflg;
  529. {
  530.   static fdb tok1fdb = { _CMTOK, TOK_WAK, NULL, (pdat) "+", NULL, NULL, NULL };
  531.   static fdb tok2fdb = { _CMTOK, 0, NULL, (pdat) "-", NULL, NULL, NULL };
  532.   static fdb tok3fdb = { _CMTOK, 0, NULL, (pdat) "**#|", NULL, NULL, NULL };
  533.   static fdb tok4fdb = { _CMTOK, 0, NULL, (pdat) "hello^friend", NULL, NULL,
  534.                NULL };
  535.   static char *t;
  536.   fdb *x;
  537.   if (helpflg) {
  538.     cmxprintf("Accepts a token.  Type 'token ?'  to see what the tokens \
  539. are.\n");
  540.   }
  541.   else {
  542.     noise("a dollar please!");        /* for you new yorkers!!! */
  543.     parse(fdbchn(&tok1fdb,&tok2fdb,&tok3fdb,&tok4fdb,NULL),&parseval,&used);
  544.     t = (char *) used->_cmdat;
  545.     confirm();
  546.     cmxprintf("Selected token: %s\n",t);
  547.   }
  548. }
  549.  
  550. /*
  551.  * parse a (possibly wild) username.
  552.  * wild cards are the same as for files, or groups.
  553.  * '*' matches anything.
  554.  * '?' matches any character
  555.  * []  match a range (may have a ^ as the first char, to negate the range).
  556.  * {}  match any of the strings inside (separated by commas).  The strings 
  557.  *     within the {} may contain any wild cards.
  558.  */
  559. user(helpflg) 
  560. int helpflg;
  561. {
  562.                     /* a wild user */
  563.   static fdb usrfdb = { _CMUSR ,USR_WILD, NULL, NULL, NULL, NULL, NULL };
  564.   static struct passwd **p;        /* returns vector of passwd entries */
  565.   struct passwd *p1;
  566.   int i;
  567.  
  568.   if (helpflg) {
  569.     cmxprintf("parses a username\n");
  570.   }
  571.   else {
  572.     noise("username");
  573.     parse(&usrfdb, &parseval, &used);
  574.     p = parseval._pvusr;
  575.     confirm();
  576. #ifndef MSDOS
  577.     for(i = 0,p1 = *p; p1 != NULL; p1 = p[++i]) {
  578.       cmxprintf("%s:%s:%d:%d:%s:%s:%s\n",p1->pw_name, p1->pw_passwd, 
  579.          p1->pw_uid, p1->pw_gid, p1->pw_gecos,p1->pw_dir,p1->pw_shell);
  580.       fflush(stdout);
  581.     }
  582. #endif
  583.   }
  584. }
  585.  
  586. /*
  587.  * parse a possibly wild group name 
  588.  */
  589. groupcmd(helpflg) 
  590. int helpflg;
  591. {
  592.   int i,j;
  593.   static fdb grpfdb = { _CMGRP ,GRP_WILD, NULL, NULL, NULL, NULL, NULL };
  594.   static struct group **g,*g1;        /* returns vector of group entries */
  595.   
  596.   if (helpflg) {
  597.     cmxprintf("parses a wild group name\n");
  598.   }
  599.   else {
  600.     noise("group name");
  601.     parse(&grpfdb, &parseval, &used);
  602.     g = parseval._pvgrp;
  603.     confirm();
  604. #ifndef MSDOS
  605.     for (j = 0, g1 = *g; g1 != NULL; g1 = g[++j]) {
  606.       cmxprintf("%s:%s:%d:",g1->gr_name, g1->gr_passwd, g1->gr_gid);
  607.       for (i = 0; g1->gr_mem[i] != NULL; i++) {
  608.     cmxprintf("%s",g1->gr_mem[i]);
  609.     if (g1->gr_mem[i+1])
  610.       putchar(',');
  611.       }
  612.       cmxprintf("\n"); fflush(stdout);
  613.     }
  614. #endif
  615.   }
  616. }
  617.  
  618. /*
  619.  * parse a wild filename.
  620.  * show the type of file on help.
  621.  */
  622.  
  623. fil(helpflg)
  624. int helpflg;
  625. {
  626.   static fdb filfdb = { _CMFIL ,FIL_NODIR, NULL, NULL, NULL, 
  627.                 NULL, NULL };
  628.   FILE *fp;
  629.   char c;
  630.   char **filelist;
  631.   int i;
  632.  
  633.   if (helpflg) {
  634.     cmxprintf("parses a possibly wild filename.\n");
  635.   }
  636.   else {
  637.     noise("to see");
  638.     parse(&filfdb, &parseval, &used);
  639.     filelist = parseval._pvfil;
  640.     confirm();
  641.     for(i = 0; filelist[i] != NULL; i++)
  642.       cmxprintf("%s\n",filelist[i]);
  643.   }
  644. }
  645.  
  646. /*
  647.  * parse a time and/or date.
  648.  */
  649. xtad(helpflg,flags)
  650. int helpflg,flags;
  651. {
  652.   static fdb tadfdb = { _CMTAD, 0, NULL, (pdat) 0, NULL, NULL, NULL };
  653.   static datime dtblk, *dt;
  654.   static char *(dows[]) = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  655.   static char *(mths[]) = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  656.       "Aug", "Sep", "Oct", "Nov", "Dec" };
  657.   int tz;
  658.   tzinf *tzi,*dttzinf();
  659.   char *tzname,tzsign;
  660.  
  661.   if (helpflg) {
  662.     cmxprintf("parse a%s%s%s\n", !(flags&DTP_NTI) ? " time" : "",
  663.           !(flags & (DTP_NTI|DTP_NDA)) ? " and" : "",
  664.           !(flags&DTP_NDA) ? " date" : "");
  665.   }
  666.   else {
  667.     tadfdb._cmffl = flags;
  668.     noise("is");
  669.     parse(&tadfdb,&parseval,&used);
  670.     dt = &parseval._pvtad;
  671.     dtblk._dtmon = dt->_dtmon;
  672.     dtblk._dtday = dt->_dtday;
  673.     dtblk._dtyr = dt->_dtyr;
  674.     dtblk._dtdow = dt->_dtdow;
  675.     dtblk._dthr = dt->_dthr;
  676.     dtblk._dtmin = dt->_dtmin;
  677.     dtblk._dtsec = dt->_dtsec;
  678.     dtblk._dttz = dt->_dttz;
  679.     dtblk._dtdst = dt->_dtdst;
  680.     confirm();
  681.     cmxprintf("%s %d-%s-%d ",dows[dtblk._dtdow], dtblk._dtday+1,
  682.         mths[dtblk._dtmon], dtblk._dtyr);
  683.     cmxprintf("%d:%d:%d-",dtblk._dthr, dtblk._dtmin, dtblk._dtsec);
  684.     tz = dtblk._dttz;
  685.     tzi = dttzinf(tz);
  686.     if (tzi == NULL) {
  687.       tzsign = tz < 0 ? '+' : '-';
  688.       if (tz < 0) tz = -tz;
  689.       cmxprintf("GMT%c%d:%d%s\n",tzsign,tz/60,tz%60,
  690.           dtblk._dtdst==0?"":" DST");
  691.     }
  692.     else
  693.       cmxprintf("%s\n",dtblk._dtdst==0?tzi->_tznam:tzi->_tzdnm);
  694.   }
  695. }
  696.     
  697. /*
  698.  * parse a time
  699.  */
  700. tim(helpflg)
  701. int helpflg;
  702. {
  703.   xtad(helpflg,DTP_NDA);
  704. }
  705.  
  706. /*
  707.  * parse a date
  708.  */
  709. dat(helpflg)
  710. int helpflg;
  711. {
  712.   xtad(helpflg,DTP_NTI);
  713. }
  714.  
  715. /*
  716.  * parse time and date
  717.  */
  718. tad(helpflg)
  719. int helpflg;
  720. {
  721.   xtad(helpflg,0);
  722. }
  723.  
  724. /*
  725.  * parse a paragraph
  726.  */
  727. char *paratxt;
  728. int paracont = FALSE;
  729. static fdb parafdb = { _CMPARA, 0, NULL, NULL, NULL, NULL, NULL };
  730. para_data pd = { NULL, NULL };
  731.  
  732. para(helpflg)
  733. int helpflg;
  734. {
  735.   if (helpflg) {
  736.     cmxprintf("parse a paragraph, using a TEXTI style form of input.\n");
  737.   }
  738.   else {
  739.     static char *tmp=NULL;
  740.  
  741.     if (!paracont) {
  742.       noise("of text");
  743.       confirm();
  744.       if (paratxt) free(paratxt);
  745.       paratxt = NULL;
  746.     }
  747.     parafdb._cmdat = (char *)&pd;
  748.     pd.buf = paratxt; 
  749.     cmcls();                /* clear the screen */
  750.     cmxprintf(" Message (End with CTRL/D\n\
  751.   Use CTRL/B to insert a file, CTRL/E to enter editor, CTRL/K to redisplay\n\
  752.   message, CTRL/L to clear screen and redisplay, CTRL/N to abort.):\n");
  753.     parse(¶fdb,&parseval,&used);
  754.     paratxt = parseval._pvpara;
  755.     if (paratxt == NULL) {
  756.       cmxprintf("Aborted!\n");
  757.     }
  758.     else {
  759.       if (tmp) 
  760.     free(tmp);
  761.       tmp = (char *)malloc(strlen(paratxt)+1);
  762.       strcpy(tmp,paratxt);
  763.       paratxt = tmp;
  764.       cmxprintf("Read %d chars.\n",strlen(paratxt)); fflush(stdout);
  765. /*
  766.  * don't free tmp, so that the continue command can still have a handle on 
  767.  * the buffer.  It will be free()ed the next time this routine is executed.
  768.  */
  769.     }
  770.     fflush(stdout);
  771.   }
  772.   paracont = FALSE;
  773. }
  774.  
  775. /*
  776.  * continue parsing a paragraph
  777.  */
  778. contpara(helpflg) {
  779.   if (helpflg) {
  780.     cmxprintf("continue editing the paragraph previously typed paragraph\n");
  781.   }
  782.   else {
  783.     noise("paragraph");
  784.     confirm();
  785.     paracont = TRUE;
  786.     para(helpflg);
  787.   }
  788. }
  789.  
  790. /*
  791.  * take commands from some other FILE *
  792.  */
  793. take() {
  794.   cmtake(toplevel);
  795. }
  796.  
  797. /*
  798.  * change the characters that define a comment
  799.  * the defaults are ";", and "!" to "!".
  800.  */
  801. comment(helpflg) {
  802.   static fdb qstfdb = { _CMQST, 0, NULL, NULL, NULL, NULL, NULL };
  803.   static char xtoeol[20], xbeg[20], xend[20];
  804.   static char toeol[20], beg[20], end[20];
  805.   if (helpflg) {
  806.     cmxprintf("set the CCMD comment characters");
  807.   }
  808.   else {
  809.     noise("To eol");
  810.     parse(&qstfdb,&parseval,&used);
  811.     strcpy(xtoeol,atmbuf);
  812.     noise("start");
  813.     parse(&qstfdb,&parseval,&used);
  814.     strcpy(xbeg,atmbuf);
  815.     noise("end");
  816.     parse(&qstfdb,&parseval,&used);
  817.     strcpy(xend,atmbuf);
  818.     confirm();
  819.     strcpy(toeol,xtoeol);
  820.     strcpy(beg,xbeg);
  821.     strcpy(end,xend);
  822.     cmcsb._cmntb = toeol;
  823.     cmcsb._cmnts = beg;
  824.     cmcsb._cmnte = end;
  825.   }
  826. }
  827.  
  828. /*
  829.  * parse a password  -- don't echo.
  830.  */
  831. password(helpflg) int helpflg; {
  832.   char *cmpasswd();
  833.   char *passwd;
  834.   if (helpflg) {
  835.     cmxprintf("parse for a password.   Don't echo.\n");
  836.   }
  837.   else {
  838.     confirm();
  839.     passwd = cmpasswd("Password:");
  840.     if (passwd == NULL) {
  841.       cmxerr("?Invalid characters in password");
  842.     }
  843.     else cmxprintf("Password: %s\n", passwd);
  844.   }
  845. }
  846.  
  847. /*
  848.  * match a string via an fdb chain.
  849.  * currently used to expand "*" as a filename.
  850.  */
  851.  
  852. domatch(helpflg) int helpflg; {
  853.   static fdb matfdb = { _CMTAD ,0, NULL, NULL, NULL, NULL, NULL };
  854.   static char *matstr = "17-May-86 13:52:06-EDT"; 
  855.   char **p,*p1;
  856.   int i;
  857.   if (helpflg) {
  858.     cmxprintf("\
  859. match a filename against the string '*'.  This tests ccmd's ability to \n\
  860. match strings in memory rather than having to rely on user input.\n");
  861.   }
  862.   else {
  863.     int ret, parselen;
  864.     static fdb tadfdb = { _CMTAD, 0, NULL, (pdat) 0, NULL, NULL, NULL };
  865.     static datime dtblk, *dt;
  866.     static char *(dows[]) = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  867.     static char *(mths[]) = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  868.                   "Aug", "Sep", "Oct", "Nov", "Dec" };
  869.     int tz;
  870.     tzinf *tzi,*dttzinf();
  871.     char *tzname,tzsign;
  872.     noise(matstr);
  873.     confirm();
  874.     ret = match(matstr,strlen(matstr),&matfdb, &parseval, &used, &parselen);
  875.     dt = &parseval._pvtad;
  876.     dtblk._dtmon = dt->_dtmon;
  877.     dtblk._dtday = dt->_dtday;
  878.     dtblk._dtyr = dt->_dtyr;
  879.     dtblk._dtdow = dt->_dtdow;
  880.     dtblk._dthr = dt->_dthr;
  881.     dtblk._dtmin = dt->_dtmin;
  882.     dtblk._dtsec = dt->_dtsec;
  883.     dtblk._dttz = dt->_dttz;
  884.     dtblk._dtdst = dt->_dtdst;
  885.     if (ret == CMxOK) {
  886.     cmxprintf("%s %d-%s-%d ",dows[dtblk._dtdow], dtblk._dtday+1,
  887.           mths[dtblk._dtmon], dtblk._dtyr);
  888.     cmxprintf("%d:%d:%d-",dtblk._dthr, dtblk._dtmin, dtblk._dtsec);
  889.     tz = dtblk._dttz;
  890.     tzi = dttzinf(tz);
  891.     if (tzi == NULL) {
  892.         tzsign = tz < 0 ? '+' : '-';
  893.         if (tz < 0) tz = -tz;
  894.         cmxprintf("GMT%c%d:%d%s\n",tzsign,tz/60,tz%60,
  895.               dtblk._dtdst==0?"":" DST");
  896.     }
  897.     else
  898.         cmxprintf("%s\n",dtblk._dtdst==0?tzi->_tznam:tzi->_tzdnm);
  899.     }
  900.     else {
  901.       cmxeprintf("domatch: ");
  902.       cmperr(ret);
  903.     }
  904.   }
  905. }
  906.  
  907. /*
  908.  * give help.
  909.  */
  910. help(helpflg) {
  911.   static fdb cmdfdb = { _CMKEY, 0, NULL, (pdat) &(cmdtab), "Command, ", 
  912.               NULL, NULL };
  913.   static fdb hlpfdb = { _CMCFM, 0, &cmdfdb, NULL, NULL, NULL, NULL };
  914.   
  915.   if (helpflg) {
  916.     cmxprintf("The help command gives help.\n");
  917.   }
  918.   else {
  919.     noise("me with");
  920.     parse(&hlpfdb,&parseval,&used);    /* parse a command */
  921.     if (used == &hlpfdb) {
  922.       cmxprintf("\
  923. This is a program to test and display some of the capabilities of the CCMD\n\
  924. package.  CCMD is a user interface package which expands upon the COMND% \n\
  925. JSYS used as a user interface by DEC's TOPS-20.  CCMD is a library, written\n\
  926. to be portable to many machines.  Currently, it runs under 4.2 BSD UNIX, and\n\
  927. MS-DOS, and will hopefully soon run on a diverse set of machines.  It is\n\
  928. hoped that this will allow a homogenious user interface to evolve on many\n\
  929. different machines.  If you are unfamiliar with the COMND interface, try the\n\
  930. '?' key.  Also try typing part of a command, and then hitting escape.\n");
  931.     }
  932.     else {
  933.       int which = parseval._pvkey;
  934.       confirm();
  935.       dohelp(which);            /* help on a subject. */
  936.     }
  937.   }
  938. }
  939.  
  940. /*
  941.  * change the character to use as a beginning switch delimiter.
  942.  */
  943. character(helpflg) {
  944.   static fdb swifdb = { _CMCHAR, 0, NULL, NULL, NULL, NULL, NULL };
  945.  
  946.   if (helpflg) {
  947.     cmxprintf("set the character that switches switch on\n");
  948.   }
  949.   else {
  950.     char c;
  951.     extern char cmswbeg;
  952.  
  953.     noise("to switch on");
  954.     parse(&swifdb,&parseval,&used);
  955.     c = parseval._pvchr;
  956.     confirm();
  957.     cmswbeg = c;
  958.   }
  959. }
  960.  
  961. shell(helpflg) int helpflg; {
  962.   static fdb txtfdb = { _CMTXT, 0, NULL, NULL, NULL, NULL, NULL };
  963.   char buf[100];
  964.   if (!helpflg) {
  965.     noise("escape");
  966.     parse(&txtfdb, &parseval, &used);
  967.     strcpy(buf, "$SHELL");
  968.     if (strlen(atmbuf) > 0) {
  969.       strcat(buf," -c \'");
  970.       strcat(buf, atmbuf);
  971.       strcat(buf, "\'");
  972.     }
  973.     confirm();
  974.     cmsystem(buf);
  975.   }
  976.   else {
  977.     cmxprintf("fork up a shell\n");
  978.   }
  979. }
  980.  
  981. nil(helpflg) {
  982.     static fdb usrfdb = { _CMUSR ,USR_WILD|USR_UPDONLY|USR_NOUPD };
  983.     int len = 0;
  984.     if (helpflg) {
  985.     cmxprintf("do nothing\n");
  986.     }
  987.     else {
  988.         noise("empty");
  989.     match("", 0, &usrfdb, &parseval, &used, &len);
  990.     confirm();
  991.     cmxprintf("t\n");
  992.     }
  993. }
  994.  
  995. history(helpflg) {
  996.     static fdb numfdb = { _CMNUM, 0, NULL, (pdat) 10, NULL, NULL, NULL };    
  997.     int n;
  998.  
  999.     parse(&numfdb, &parseval, &used);
  1000.     n = parseval._pvint;
  1001.     confirm();
  1002.     cmhst(n);
  1003.     printf("setting history to %d\n",n);
  1004. }
  1005.